package com.kvest.map.mapview.engine.controller;

import android.annotation.TargetApi;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import com.kvest.map.mapview.engine.model.AbstractModel;

import java.util.Arrays;

/**
 * Created with IntelliJ IDEA.
 * User: Kvest
 * Date: 05.05.13
 * Time: 11:15
 * To change this template use File | Settings | File Templates.
 */
public class MapController implements View.OnTouchListener{
    private static final int MAX_POINTERS = 5;
    private static final double MIN_SCALE_DELTA = 1;

    private AbstractModel model;

    private int touchCount;
    private boolean[] touches;
    private float[] xs;
    private float[] ys;
    private float xKoeff;
    private float yKoeff;

    public MapController(View view, AbstractModel model) {
        this.model = model;
        view.setOnTouchListener(this);

        //ToDo рассчитывать коэффициенты
        xKoeff = 0.01f;
        yKoeff = 0.01f;

        touchCount = 0;
        touches = new boolean[MAX_POINTERS];
        xs = new float[MAX_POINTERS];
        ys = new float[MAX_POINTERS];
        clear();
    }

    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        // событие
        int actionMask = motionEvent.getActionMasked();
        // индекс касания
        int pointerIndex = motionEvent.getActionIndex();
        // число касаний
        int pointerCount = Math.min(motionEvent.getPointerCount(), MAX_POINTERS);

        if (pointerIndex >= pointerCount) {
            return true;
        }

        switch (actionMask) {
            case MotionEvent.ACTION_DOWN: // первое касание
            case MotionEvent.ACTION_POINTER_DOWN: // последующие касания
                pointerDown(pointerIndex, motionEvent.getX(pointerIndex), motionEvent.getY(pointerIndex));
                ++touchCount;
                break;
            case MotionEvent.ACTION_UP: // прерывание последнего касания
                clear();
                break;
            case MotionEvent.ACTION_POINTER_UP: // прерывания касаний
                pointerUp(pointerIndex);
                --touchCount;
                break;
            case MotionEvent.ACTION_MOVE: // движение
                pointerMove(pointerIndex, motionEvent.getX(pointerIndex), motionEvent.getY(pointerIndex));
                break;
        }

        return true;
    }

    private void clear() {
        touchCount = 0;
        Arrays.fill(touches, false);
        Arrays.fill(xs, 0.0f);
        Arrays.fill(ys, 0.0f);
    }

    private void pointerDown(int pointerIndex, float x, float y) {
        touches[pointerIndex] = true;
        xs[pointerIndex] = x;
        ys[pointerIndex] = y;
    }

    private void pointerUp(int pointerIndex) {
        touches[pointerIndex] = false;
        xs[pointerIndex] = 0.0f;
        ys[pointerIndex] = 0.0f;
    }

    private void pointerMove(int pointerIndex, float x, float y) {
        //Пока обрабатываем два касания - масштабирование и остальные варианты - перемещение(смотрим перемещение по 0 пальцу)
        if (touchCount == 2) {
            scaleMap(pointerIndex, x, y);
        } else {
            moveMap(pointerIndex, x, y);
        }
    }

    private void scaleMap(int pointerIndex, float x, float y) {
        //Перемещение смотрим только по 0 и 1 пальцу
        if (pointerIndex != 0 && pointerIndex != 1) {
            return;
        }

        int secondPointer = pointerIndex == 0 ? 1 : 0;
        double delta = Math.sqrt(Math.pow(xs[pointerIndex] - xs[secondPointer], 2.0) +
                                Math.pow(ys[pointerIndex] - ys[secondPointer], 2.0));

        //save new coordinates
        xs[pointerIndex] = x;
        ys[pointerIndex] = y;

        delta -= Math.sqrt(Math.pow(xs[pointerIndex] - xs[secondPointer], 2.0) +
                           Math.pow(ys[pointerIndex] - ys[secondPointer], 2.0));

        if (Math.abs(delta) > MIN_SCALE_DELTA) {
            if (delta > 0) {
                model.zoomIn();
            } else {
                model.zoomOut();
            }
        }
    }

    private void moveMap(int pointerIndex, float x, float y) {
        //Перемещение смотрим только по 0 пальцу
        if (pointerIndex != 0) {
            return;
        }

        //calculate delta
        float dx = (xs[pointerIndex] - x) * xKoeff;
        float dy = (ys[pointerIndex] - y) * yKoeff;

        if (Math.abs(dx) > 0 || Math.abs(dy) > 0) {
            model.moveSmoothly(dx, dy);
        }

        //save new coordinates
        xs[pointerIndex] = x;
        ys[pointerIndex] = y;
    }
}
